#include "openmove_Prefix.h"
#include "SceneBase.h"
#include "OgreEngine.h"
#include "ExampleFrameListener.h"
#include "SkeletalAnimationFrameListener.h"
#include "OgreExternalTextureSourceManager.h"
#include "OgreExternalTextureSource.h"
#include "SceneInBedHaut.h"
#include "SimpleFrameListener.h"

CSceneInBedHaut :: CSceneInBedHaut(COgreEngine &Creator, const String & Name, const int pos) : CSceneBase(Creator, Name, pos), m_pPluie(NULL), m_pPluieTop(NULL), m_ReflectCam(NULL), m_PlaneEnt(NULL), m_Play(false), m_CamFrame(0), m_LastTime(-1), m_CurrentSpeed(0)
{
}

CSceneInBedHaut :: ~CSceneInBedHaut(void)
{
}

void CSceneInBedHaut :: Create(TCreatorEntities const &CreatorEntities, TCreatorNodes const &CreatorNodes, TCreatorLights const &CreatorLights, ENetConfig IsClient, Vector3 &CameraStartPos)
{	
	CSceneBase::Create(CreatorEntities, CreatorNodes, CreatorLights, IsClient, CameraStartPos);

/*


	MaterialPtr mat = (MaterialPtr)MaterialManager::getSingleton().getByName("inbed_haut-sol/blinn1");
	Pass *pass = mat->getTechnique(0)->getPass(0);
	TextureUnitState *texState;

	SProjectorFrustum DecalFrustum = CreateProjector("InBedDecalProjectorNode", Vector3(-24.001f, 458.252f, -42.394f), Vector3(-0.1f, -1.0f, 0.1f));
	//pDecalFrustum->setFOVy(Degree(90));
	DecalFrustum.m_Decal->setAspectRatio(12.0f / 3.0f);

	pass->setAmbient(1.0, 1.0, 1.0);
	//pass->setSceneBlending(SBT_MODULATE);

	texState = pass->createTextureUnitState("plante_video2");
	texState->setProjectiveTexturing(true, DecalFrustum.m_Decal);
	texState->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
	texState->setTextureFiltering(FO_NONE, FO_NONE, FO_NONE);
	//texState->setColourOperation(LBO_REPLACE);
	texState->setTextureBorderColour(ColourValue(0.0f, 0.0f, 0.0f, 0.0f));
	*/

	//m_Compositors.push_back("InBedCustomShadow");
}

void CSceneInBedHaut :: Attach(void)
{
	CSceneBase::Attach();

	m_Play = false;
	m_LastTime = m_Timer.getSeconds();
	m_CamFrame = 0;
	m_CurrentSpeed = 0;

	//m_pCurrentCamera->setPosition(-201.430, 921.781, -22.724);
	m_pCurrentCamera->rotate(Vector3(-0.57735, 0.57735, 0.57735), Radian(2.0944));
	//m_OgreEngine.m_pViewPort->setBackgroundColour(ColourValue(0.0f, 0.0f, 0.0f, 1.0f));

	//m_OgreEngine.m_pCurrentSceneManager->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
	//m_OgreEngine.m_pCurrentSceneManager->setShadowFarDistance(3000);
	//m_OgreEngine.m_pCurrentSceneManager->setShadowTextureSize(2048);
	//m_OgreEngine.m_pCurrentSceneManager->setShadowColour(ColourValue::Black);

	Light *light = findLight(String("InBedHaut-pointLight2"));
	light->setSpotlightRange(Degree(20), Degree(30));

	m_OgreEngine.m_pCurrentSceneManager->setShadowTextureReceiverMaterial("openmove.blur");
	m_OgreEngine.m_pCurrentSceneManager->setShadowTextureCasterMaterial("HardwareSkiningOneLight");


	MaterialPtr mat = MaterialManager::getSingleton().getByName("decor-inbed_haut_nid/lambert7");
	
	ResourcePtr resource = TextureManager::getSingleton().getByName("Ogre/ShadowTexture0");
	Texture * mCurrentShadowTexture = reinterpret_cast<Texture *>(resource.getPointer());
	Camera *cam = mCurrentShadowTexture->getBuffer()->getRenderTarget()->getViewport(0)->getCamera();
	mat->getTechnique(0)->getPass(1)->getTextureUnitState(0)->setProjectiveTexturing(true, cam);
	
/*
	CompositorInstance *pCompositor = CompositorManager::getSingleton().addCompositor(mCurrentShadowTexture->getBuffer()->getRenderTarget()->getViewport(0), "InBedCustomShadow");
	if (NULL != pCompositor)
	{
		pCompositor->setEnabled(true);

		addShadows(findEntity(String("decor-inbed_haut_nid")), pCompositor, cam);
		addShadows(findEntity(String("inbed_haut_ana")), pCompositor, cam, "InBed_Nco_Shadow");
		addShadows(findEntity(String("inbed_haut_nco")), pCompositor, cam, "InBed_Ana_Shadow");
	}

	Entity *ent = findEntity(String("inbed_haut_ana"));
	ent->setVisibilityFlags(0x3);

	ent = findEntity(String("inbed_haut_nco"));
	ent->setVisibilityFlags(0x5);
*/
}


void CSceneInBedHaut :: addShadows(Entity *ent, CompositorInstance *pCompositor, Camera *cam, String const &name)
{
	Mesh::SubMeshIterator it = ent->getMesh()->getSubMeshIterator();
	while (it.hasMoreElements())
	{
		SubMesh *mesh = it.getNext();
		MaterialPtr mat = MaterialManager::getSingleton().getByName(mesh->getMaterialName());

		Technique *technique = mat->getTechnique(0);
		Pass *pass = NULL;
		for (unsigned short i = 0; i < technique->getNumPasses(); ++i)
		{
			Pass *curPass = technique->getPass(i);
			if (curPass->getName() == "ShadowReceiver")
			{
				pass = curPass;
				break;
			}
		}

		if (NULL == pass)
		{
			pass = technique->createPass();
			pass->setLightingEnabled(false);
			pass->setDepthWriteEnabled(false);
			pass->setSceneBlending(SBT_MODULATE);
			pass->setCullingMode(CULL_CLOCKWISE);
			pass->setManualCullingMode(MANUAL_CULL_FRONT);
			pass->setDepthFunction(CMPF_LESS_EQUAL);
			pass->setDepthBias(1);
		}

		if (NULL == pass)
			return;

		if ("" == name)
		{
			addNamedShadows(pass, pCompositor, cam, "InBed_Ana_Shadow");
			addNamedShadows(pass, pCompositor, cam, "InBed_Nco_Shadow");
		}
		else
		{
			addNamedShadows(pass, pCompositor, cam, name);
		}
	}
}

void CSceneInBedHaut :: addNamedShadows(Pass *pass, CompositorInstance *pCompositor, Camera *cam, String const &name)
{
	if (pass == NULL || NULL == pCompositor || NULL == cam)
		return;

	Technique *technique = pass->getParent();
	ushort depthBias = 0;
	for (unsigned short i = 0; i < technique->getNumPasses(); ++i)
	{
		ushort bias = technique->getPass(i)->getDepthBias();
		if (bias > depthBias)
			depthBias = bias;
	}
	++depthBias;

	TextureUnitState *state;
	state = pass->createTextureUnitState();
	state->setTextureName(pCompositor->getTextureInstanceName(name));
	state->setProjectiveTexturing(true, cam);
	state->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
}

bool CSceneInBedHaut :: frameStarted(const FrameEvent& evt)
{
	CSceneBase::frameStarted(evt);

	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_Z) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_IBE_StartCamera, 3.0f);
	} 
	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_X) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_IBE_StopCamera, 3.0f);
	} 


	if (m_LastTime != -1)
	{
	Real timeElapsed = m_Timer.getSeconds() - m_LastTime;
	if (m_Play)
	{
		m_CamFrame += timeElapsed;
		m_CurrentSpeed = std::min(m_CurrentSpeed + 0.05f, 1.0f);
	}
	else
	{
		m_CamFrame += timeElapsed * m_CurrentSpeed;
		m_CurrentSpeed = std::max(m_CurrentSpeed - 0.05f, 0.0f);
	}
	}

	m_LastTime = m_Timer.getSeconds();

	return (true);
}

void CSceneInBedHaut :: processEvents(void)
{
	CSceneBase::processEvents();

	for (TEvents::iterator It = m_Events.begin(); It != m_Events.end(); ++It)
	{
		switch (It->m_Packet.eventid)
		{
			case SOpenMoveDisplayPacket::e_IBE_StartCamera:
			{
				if (m_Timer.getSeconds() > 20.0f)
					m_Play = true;
				break;
			}
			case SOpenMoveDisplayPacket::e_IBE_StopCamera:
			{
				if (m_Timer.getSeconds() > 20.0f)
					m_Play = false;
				break;
			}
		}
	}

	if (m_NetConfig == e_NCNone || m_NetConfig == e_NCServer)
	{
		Entity *ent = findEntity(String("decor-inbed_haut_camera"));
		if (NULL != ent && ent->hasSkeleton())
		{
			AnimationState *state = ent->getAnimationState("camera");
			if (NULL != state)
			{			
				state->setTimePosition(m_CamFrame);
			}
		}
	}
}